﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sinacor.Infra.Common.Validation;
using Sinacor.Infra.Common.Exceptions.FaultContracts;
using System.ServiceModel;

namespace Sinacor.Infra.Common.Exceptions
{
    /// <summary>
    /// Exceção disparada para erros de validação
    /// </summary>
    public class ValidationException : BaseLogException
    {
        /// <summary>
        /// Construtor padrão
        /// </summary>
        public ValidationException()
            : this(null, null)
        {
        }

        /// <summary>
        /// Construtor que adiciona um erro de validação
        /// </summary>
        /// <param name="errorNumber">Número do erro</param>
        /// <param name="parameters">Parâmetros para a mensagem de erro</param>
        public ValidationException(int errorNumber, params object[] parameters)
            : this(null, null)
        {
            this.AddError(errorNumber, parameters);
        }

        /// <summary>
        /// Construtor que inicializa InnerException
        /// </summary>
        /// <param name="innerException">Erro que originou a Exception</param>
        public ValidationException(Exception innerException)
            : this(null, innerException)
        {
        }

        /// <summary>
        /// Construtor que inicializa Message e InnerException
        /// </summary>
        /// <param name="message">Mensagem de erro</param>
        /// <param name="innerException">Erro que originou a Exception</param>
        public ValidationException(string message, Exception innerException)
            : base(message, innerException)
        {
            _message = message;
        }

        private string _message;
        /// <summary>
        /// Mensagem de erro
        /// </summary>
        public override string Message
        {
            get
            {
                return _message;
            }
        }

        private Dictionary<int, ValidationError> _validationErrors = new Dictionary<int, ValidationError>();
        /// <summary>
        /// Erros de validação
        /// </summary>
        public Dictionary<int, ValidationError> ValidationErrors
        {
            get { return _validationErrors; }
        }

        /// <summary>
        /// Adiciona um erro de validação
        /// </summary>
        /// <param name="errorNumber">Número do erro</param>
        /// <param name="parameters">Parâmetros para a mensagem de erro</param>
        /// <returns>true se o erro for adicionado, false se o número do erro já existir</returns>
        public bool AddError(int errorNumber, params object[] parameters)
        {
            if (!_validationErrors.ContainsKey(errorNumber))
            {
                _validationErrors.Add(errorNumber, new ValidationError(errorNumber, parameters.ToList()));
                return true;
            }
            return false;
        }

        /// <summary>
        /// Cria instância da falta
        /// </summary>
        /// <returns>Instância da falta</returns>
        protected override BaseFault CreateFaultInstance()
        {
            return new ValidationFault();
        }

        /// <summary>
        /// Cria uma falta a partir da exceção
        /// </summary>
        /// <returns>Falta com o erro</returns>
        public override BaseFault CreateFault()
        {
            ValidationFault fault = (ValidationFault)base.CreateFault();

            this.ValidationErrors.ToList().ForEach(e => fault.ValidationErrors.Add(e.Key, e.Value));

            return fault;
        }

        /// <summary>
        /// Cria uma exceção de falta a partir da exceção
        /// </summary>
        /// <returns>Falta com o erro</returns>
        public override FaultException CreateFaultException()
        {
            return new FaultException<ValidationFault>((ValidationFault)this.CreateFault(), this.Message);
        }

        /// <summary>
        /// Gera a mensagem de erro a partir dos Validation Errors
        /// </summary>
        public void ConfigureMessage()
        {
            _message = this.ValidationErrors.Values.Aggregate<ValidationError, string>(string.Empty, (init, error) => (!string.IsNullOrEmpty(init) ? init + Environment.NewLine : string.Empty) + error.ErrorMessage);
        }
    }
}
